library(dplyr)
Registered S3 method overwritten by 'dplyr':
  method           from
  print.rowwise_df     

Attaching package: ‘dplyr’

The following objects are masked from ‘package:stats’:

    filter, lag

The following objects are masked from ‘package:base’:

    intersect, setdiff, setequal, union
library(devtools)
Loading required package: usethis
library(leaflet)
Registered S3 methods overwritten by 'htmltools':
  method               from         
  print.html           tools:rstudio
  print.shiny.tag      tools:rstudio
  print.shiny.tag.list tools:rstudio
Registered S3 method overwritten by 'htmlwidgets':
  method           from         
  print.htmlwidget tools:rstudio

1. Location of Severe Fires

building_fire <- read.csv("/Users/carolineyu/Documents/1111/course_materials/Exercises/07_fire/building_fires.csv")
FDNY <- read.csv("/Users/carolineyu/Documents/1111/course_materials/Exercises/07_fire/FDNY_Firehouse_Listing.csv")
building_fire$HIGHEST_LEVEL_DESC <- case_when( building_fire$HIGHEST_LEVEL_DESC == "0 - Initial alarm" ~"0 - Initial alarm",
building_fire$HIGHEST_LEVEL_DESC == " 11 - First Alarm " ~ "1 - Initial alarm, less than 10-75",
building_fire$HIGHEST_LEVEL_DESC == " 1 - More than initial alarm, less than Signal 7-5" ~ " 1 - More than initial alarm, less than Signal 7-5 ",
building_fire$HIGHEST_LEVEL_DESC %in% c("2 - 2nd alarm ","22 - Second Alarm") ~ "2 - 2nd alarm",
building_fire$HIGHEST_LEVEL_DESC %in% c("3 - 3rd alarm ", " 33 - Third Alarm ") ~ "3 - 3rd alarm",
building_fire$HIGHEST_LEVEL_DESC%in% c("4 - 4th alarm", " 44 - Fourth Alarm") ~ "4 - 4th alarm",
building_fire$HIGHEST_LEVEL_DESC %in% c(" 5 - 5th alarm", " 55 - Fifth Alarm ") ~ " 5 - 5th alarm",
building_fire$HIGHEST_LEVEL_DESC %in% c("7 - Signal 7-5", "75 - All Hands Working") ~ "7 - Signal 7-5")
Highest_severity <- building_fire %>%
  filter(HIGHEST_LEVEL_DESC == "7 - Signal 7-5")
content <- paste("Severity:", Highest_severity$HIGHEST_LEVEL_DESC,"<br/c>",
                 "When:",Highest_severity$INCIDENT_DATE_TIME,"<br/c>",
                 "Where:",Highest_severity$PROPERTY_USE_DESC,"<br/c")
m <- leaflet(Highest_severity) %>%
  addTiles()
m1 <- m %>%
  addCircles(lng = ~lon, lat = ~lat, popup = content)

2. Layers and Clusters

  1. Color by Type of Property
Highest_severity$PROPERTY_USE_DESC <- case_when(grepl("dwelling",Highest_severity$PROPERTY_USE_DESC)== TRUE | Highest_severity$PROPERTY_USE_DESC %in% c("400 - Residential, other  ","439 - Boarding/rooming house, residential hotels "," 449 - Hotel/motel, commercial"," 460 - Dormitory-type residence, other ","464 - Barracks, dormitory ") ~ "Dwelling, Residential",Highest_severity$PROPERTY_USE_DESC%in% c(" 161 - Restaurant or cafeteria") ~"Restaurant", Highest_severity$PROPERTY_USE_DESC%in% c("881 - Parking garage, (detached residential garage)","965 - Vehicle parking area "," 882 - Parking garage, general vehicle  ") ~"Parking", Highest_severity$PROPERTY_USE_DESC%in% c("564 - Laundry, dry cleaning ","579 - Motor vehicle or boat sales, services, repair","559 - Recreational, hobby, home repair sales, pet store ","500 - Mercantile, business, other   ","549 - Specialty shop"," 519 - Food and beverage sales, grocery store ","580 - General retail, other","557 - Personal service, including barber & beauty shops ","511 - Convenience store    ","539 - Household goods, sales, repairs ","183 - Movie theater ","180 - Studio/theater, other ","160 - Eating, drinking places, other ","529 - Textile, wearing apparel sales","581 - Department or discount store","186 - Film/movie production studio","181 - Live performance theater","254 - Day care, in commercial property","161 - Restaurant or cafeteria","142 - Clubhouse ","140 - Clubs, other","143 - Yacht Club ","162 - Bar or nightclub","144 - Casino, gambling clubs","141 - Athletic/health club") ~"Commercial Property", Highest_severity$PROPERTY_USE_DESC%in% c(" 131 - Church, mosque, synagogue, temple, chapel")  ~ "Religious Places", Highest_severity$PROPERTY_USE_DESC%in% c(" 173 - Bus station     ","170 - Passenger terminal, other ","174 - Rapid transit station ")  ~ "Public Transportation", grepl("Clinic",Highest_severity$PROPERTY_USE_DESC) == TRUE | Highest_severity$PROPERTY_USE_DESC%in% c("331 - Hospital - medical or psychiatric ","311 - 24-hour care Nursing homes, 4 or more persons"," 332 - Hospices "," 300 - Health care, detention, & correction, other ","342 - Doctor, dentist or oral surgeon office"," 321 - Mental retardation/development disability facility"," 340 - Clinics, doctors offices, hemodialysis cntr, other","363 - Reformatory, juvenile detention center") ~ "Clinic",
Highest_severity$PROPERTY_USE_DESC%in% c("210 - Schools, non-adult, other","241 - Adult education center, college classroom  ","215 - High school/junior high school/middle school","211 - Preschool","213 - Elementary school, including kindergarten")  ~ "School", Highest_severity$PROPERTY_USE_DESC%in% c("123 - Stadium, arena"," 931 - Open land or field ","962 - Residential street, road or residential driveway  ","322 - Alcohol or substance abuse recovery center","610 - Energy production plant, other","926 - Outbuilding, protective shelter ","000 - Property Use, other"," 981 - Construction site","459 - Residential board and care  "," 152 - Museum ","130 - Places of worship, funeral parlors, other","963 - Street or road in commercial area ","648 - Sanitation utility","110 - Fixed-use recreation places, other","571 - Service station, gas station ","182 - Auditorium, concert hall  "," 808 - Outbuilding or shed "," 121 - Ballroom, gymnasium  ","112 - Billiard center, pool hall ","569 - Professional supplies, services ","124 - Playground","635 - Computer center","134 - Funeral parlor","984 - Industrial plant yard - area","629 - Laboratory or science lababoratory","936 - Vacant lot","250 - Day care, other (Conversion only)","615 - Electric-generating plant ","639 - Communications center","898 - Dock, marina, pier, wharf ","952 - Railroad yard ")  ~ "Public Area",Highest_severity$PROPERTY_USE_DESC%in% c("891 - Warehouse","899 - Residential or self-storage units ","880 - Vehicle storage, other  ","800 - Storage, other","839 - Refrigerated storage ","807 - Outside material storage area")  ~ "Warehouse/Storage",Highest_severity$PROPERTY_USE_DESC%in% c(" 599 - Business office","593 - Office:  veterinary or research ","150 - Public or government, other   ","596 - Post office or mailing firms","365 - Police station","155 - Courthouse","Bank")  ~ "Office")
pal = colorFactor("Set1", domain = Highest_severity$PROPERTY_USE_DESC)
color_pro = pal(Highest_severity$PROPERTY_USE_DESC)
m2 <- m %>%
  addCircles(lng = ~lon, lat = ~lat, color = color_pro,popup = ~as.character(Highest_severity$PROPERTY_USE_DESC)) %>%
addLegend(pal = pal, values = ~ Highest_severity$PROPERTY_USE_DESC, title = "Type of Property")
m2
  1. Cluster
m3 <- m %>%
addCircleMarkers(lng = ~lon, lat = ~lat,color = color_pro, popup = content, clusterOptions = markerClusterOptions())
m3

3. Fire House

m_l1 <- leaflet() %>%
addTiles()%>%
addCircleMarkers(data = Highest_severity ,group = "Incidents", radius  = ~ Highest_severity$UNITS_ONSCENE,popup = content) %>%
addCircleMarkers(data = FDNY,group = "Firehouses",color = "#F05",popup = ~as.character(FDNY$FacilityName),clusterOptions = markerClusterOptions()) %>%
addLayersControl(
baseGroups = c("NYCmap"),
overlayGroups = c("Incidents","Firehouses"))
Assuming "lon" and "lat" are longitude and latitude, respectively
Assuming "Longitude" and "Latitude" are longitude and latitude, respectively
Data contains 5 rows with either missing or invalid lat/lon values and will be ignored
m_l1

4. Distance from Firehouse and Response Time

  1. Calculate Distance
building_fire1<- building_fire %>%
mutate(distime = difftime(strptime(as.character(building_fire$ARRIVAL_DATE_TIME),"%m/%d/%Y %I:%M:%S %p"),strptime(as.character(building_fire$INCIDENT_DATE_TIME),"%m/%d/%Y %I:%M:%S %p"),units = "secs"))
library(geosphere)
library(SoDA)
library(ggplot2)
fire_lon_lat <- data.frame(building_fire1$lon, building_fire1$lat)
FDNY_lon_lat <- data.frame(FDNY$Longitude, FDNY$Latitude)
a <-  distm(as.vector(fire_lon_lat),as.vector(FDNY_lon_lat),fun = distGeo)
building_fire2 <- building_fire1 %>%
mutate(mindist = NA)
for (i in 1:nrow(a)) {
building_fire2$mindist[i] <- min(a[i,],na.rm = TRUE)
}
p_distance <- ggplot(building_fire2, aes(x = mindist, y = distime)) + geom_point() + xlim(0,5000) + ylim(0,1000) + facet_wrap(as.factor(building_fire2$HIGHEST_LEVEL_DESC)) + geom_smooth() + labs(x="Nearest Firehouse in meters", y = "First arrival in secs", title = "Distance From Firehouse V.S. Response Time")
p_distance

  1. Map of Response Times
library(rgdal)
Loading required package: sp
rgdal: version: 1.4-8, (SVN revision 845)
 Geospatial Data Abstraction Library extensions to R successfully loaded
 Loaded GDAL runtime: GDAL 2.4.2, released 2019/06/28
 Path to GDAL shared files: /Library/Frameworks/R.framework/Versions/3.6/Resources/library/rgdal/gdal
 GDAL binary built with GEOS: FALSE 
 Loaded PROJ.4 runtime: Rel. 5.2.0, September 15th, 2018, [PJ_VERSION: 520]
 Path to PROJ.4 shared files: /Library/Frameworks/R.framework/Versions/3.6/Resources/library/rgdal/proj
 Linking to sp version: 1.3-2 
library(geojson)

Attaching package: ‘geojson’

The following object is masked from ‘package:graphics’:

    polygon
library(geojsonio)

Attaching package: ‘geojsonio’

The following object is masked from ‘package:geosphere’:

    centroid

The following object is masked from ‘package:devtools’:

    lint

The following object is masked from ‘package:base’:

    pretty
nycity <- readOGR("/Users/carolineyu/Desktop/borough_boundaries.geojson", verbose = FALSE)
content_time <- paste("Severity:", building_fire2$HIGHEST_LEVEL_DESC,"<br/c>",
"When:",building_fire2$INCIDENT_DATE_TIME,"<br/c>",
"Property Type:",building_fire2$PROPERTY_USE_DESC,"<br/c",
"Response Time:",building_fire2$distime,"<br/c")
building_fire3 <- building_fire2 %>%
  group_by(BOROUGH_DESC, HIGHEST_LEVEL_DESC)%>%
  summarise(avg = mean(distime, na.rm = TRUE))
building_fire3$BOROUGH_DESC <- substring(building_fire3$BOROUGH_DESC, 5)
nycity_severity <- left_join(nycity@data,building_fire3, by = c("boro_name"="BOROUGH_DESC"))
Column `boro_name`/`BOROUGH_DESC` joining factor and character vector, coercing into character vector
mypalette <- colorNumeric(palette ="YlOrRd", domain = as.numeric(building_fire3$avg),c(180,250))
NYC_Fires <- leaflet() %>% 
  addTiles() %>%
  addPolygons(data = nycity,fillOpacity = 1,fillColor = ~mypalette(as.numeric(building_fire3$avg)))
NYC_Fires
library(lubridate)
building_fire2$YEAR <- substring(building_fire2$INCIDENT_DATE_TIME,7,10)
yearly <- building_fire2 %>%
  group_by(YEAR, BOROUGH_DESC) %>%
  summarise(avg = mean(distime, na.rm = TRUE))
library(reshape )
yearly$BOROUGH_DESC <- substring(yearly$BOROUGH_DESC, 5)
nyc_by_year <- full_join(yearly, nycity@data, by = c("BOROUGH_DESC" = "boro_name" ))
mypalette1 <- colorNumeric("YlOrRd", domain = as.numeric(nyc_by_year$avg), c(180,250))
year2013 <- left_join(nycity@data, yearly[yearly$YEAR == 2013, ], by = c("boro_name" = "BOROUGH_DESC"))
Column `boro_name`/`BOROUGH_DESC` joining factor and character vector, coercing into character vector
nyc2013 <- leaflet()%>%
  addTiles() %>%
  addPolygons(data = nycity, fillColor = ~ mypalette1(as.numeric(year2013$avg)),
              fillOpacity = 1)%>%
  addLegend(pal = mypalette1, values = as.numeric(nyc_by_year$avg), title = "YEAR 2013", "topright")
year2014 <- left_join(nycity@data, yearly[yearly$YEAR == 2014, ], by = c("boro_name" = "BOROUGH_DESC"))
Column `boro_name`/`BOROUGH_DESC` joining factor and character vector, coercing into character vector
nyc2014 <- leaflet()%>%
  addTiles() %>%
  addPolygons(data = nycity, fillColor = ~ mypalette1(as.numeric(year2014$avg)),
              fillOpacity = 1)%>%
  addLegend(pal = mypalette1, values = as.numeric(nyc_by_year$avg), title = "YEAR 2014", "topright")
year2015 <- left_join(nycity@data, yearly[yearly$YEAR == 2015, ], by = c("boro_name" = "BOROUGH_DESC"))
Column `boro_name`/`BOROUGH_DESC` joining factor and character vector, coercing into character vector
nyc2015<- leaflet()%>%
  addTiles() %>%
  addPolygons(data = nycity, fillColor = ~ mypalette1(as.numeric(year2015$avg)),
              fillOpacity = 1)%>%
  addLegend(pal = mypalette1, values = as.numeric(nyc_by_year$avg), title = "YEAR 2015", "topright")
year2016 <- left_join(nycity@data, yearly[yearly$YEAR == 2016, ], by = c("boro_name" = "BOROUGH_DESC"))
Column `boro_name`/`BOROUGH_DESC` joining factor and character vector, coercing into character vector
nyc2016 <- leaflet()%>%
  addTiles() %>%
  addPolygons(data = nycity, fillColor = ~ mypalette1(as.numeric(year2016$avg)),
              fillOpacity = 1)%>%
  addLegend(pal = mypalette1, values = as.numeric(nyc_by_year$avg), title = "YEAR 2016", "topright")
year2017 <- left_join(nycity@data, yearly[yearly$YEAR == 2017, ], by = c("boro_name" = "BOROUGH_DESC"))
Column `boro_name`/`BOROUGH_DESC` joining factor and character vector, coercing into character vector
nyc2017 <- leaflet()%>%
  addTiles() %>%
  addPolygons(data = nycity, fillColor = ~ mypalette1(as.numeric(year2017$avg)),
              fillOpacity = 1)%>%
  addLegend(pal = mypalette1, values = as.numeric(nyc_by_year$avg), title = "YEAR 2017", "topright")
year2018 <- left_join(nycity@data, yearly[yearly$YEAR == 2018, ], by = c("boro_name" = "BOROUGH_DESC"))
Column `boro_name`/`BOROUGH_DESC` joining factor and character vector, coercing into character vector
nyc2018 <- leaflet()%>%
  addTiles() %>%
  addPolygons(data = nycity, fillColor = ~ mypalette1(as.numeric(year2018$avg)),
              fillOpacity = 1)%>%
  addLegend(pal = mypalette1, values = as.numeric(nyc_by_year$avg), title = "YEAR 2018", "topright")
library(mapview)
leafsync::sync(nyc2013,nyc2014,nyc2015,nyc2016,nyc2017,nyc2018)
LS0tCnRpdGxlOiAiUiBOb3RlYm9vayIKb3V0cHV0OiBodG1sX25vdGVib29rCi0tLQoKYGBge3J9CmxpYnJhcnkoZHBseXIpCmxpYnJhcnkoZGV2dG9vbHMpCmxpYnJhcnkobGVhZmxldCkKYGBgCgojIyMjIDEuIExvY2F0aW9uIG9mIFNldmVyZSBGaXJlcwpgYGB7cn0KYnVpbGRpbmdfZmlyZSA8LSByZWFkLmNzdigiL1VzZXJzL2Nhcm9saW5leXUvRG9jdW1lbnRzLzExMTEvY291cnNlX21hdGVyaWFscy9FeGVyY2lzZXMvMDdfZmlyZS9idWlsZGluZ19maXJlcy5jc3YiKQpGRE5ZIDwtIHJlYWQuY3N2KCIvVXNlcnMvY2Fyb2xpbmV5dS9Eb2N1bWVudHMvMTExMS9jb3Vyc2VfbWF0ZXJpYWxzL0V4ZXJjaXNlcy8wN19maXJlL0ZETllfRmlyZWhvdXNlX0xpc3RpbmcuY3N2IikKYGBgCgoKYGBge3J9CmJ1aWxkaW5nX2ZpcmUkSElHSEVTVF9MRVZFTF9ERVNDIDwtIGNhc2Vfd2hlbiggYnVpbGRpbmdfZmlyZSRISUdIRVNUX0xFVkVMX0RFU0MgPT0gIjAgLSBJbml0aWFsIGFsYXJtIiB+IjAgLSBJbml0aWFsIGFsYXJtIiwKYnVpbGRpbmdfZmlyZSRISUdIRVNUX0xFVkVMX0RFU0MgPT0gIiAxMSAtIEZpcnN0IEFsYXJtICIgfiAiMSAtIEluaXRpYWwgYWxhcm0sIGxlc3MgdGhhbiAxMC03NSIsCmJ1aWxkaW5nX2ZpcmUkSElHSEVTVF9MRVZFTF9ERVNDID09ICIgMSAtIE1vcmUgdGhhbiBpbml0aWFsIGFsYXJtLCBsZXNzIHRoYW4gU2lnbmFsIDctNSIgfiAiIDEgLSBNb3JlIHRoYW4gaW5pdGlhbCBhbGFybSwgbGVzcyB0aGFuIFNpZ25hbCA3LTUgIiwKYnVpbGRpbmdfZmlyZSRISUdIRVNUX0xFVkVMX0RFU0MgJWluJSBjKCIyIC0gMm5kIGFsYXJtICIsIjIyIC0gU2Vjb25kIEFsYXJtIikgfiAiMiAtIDJuZCBhbGFybSIsCmJ1aWxkaW5nX2ZpcmUkSElHSEVTVF9MRVZFTF9ERVNDICVpbiUgYygiMyAtIDNyZCBhbGFybSAiLCAiIDMzIC0gVGhpcmQgQWxhcm0gIikgfiAiMyAtIDNyZCBhbGFybSIsCmJ1aWxkaW5nX2ZpcmUkSElHSEVTVF9MRVZFTF9ERVNDJWluJSBjKCI0IC0gNHRoIGFsYXJtIiwgIiA0NCAtIEZvdXJ0aCBBbGFybSIpIH4gIjQgLSA0dGggYWxhcm0iLApidWlsZGluZ19maXJlJEhJR0hFU1RfTEVWRUxfREVTQyAlaW4lIGMoIiA1IC0gNXRoIGFsYXJtIiwgIiA1NSAtIEZpZnRoIEFsYXJtICIpIH4gIiA1IC0gNXRoIGFsYXJtIiwKYnVpbGRpbmdfZmlyZSRISUdIRVNUX0xFVkVMX0RFU0MgJWluJSBjKCI3IC0gU2lnbmFsIDctNSIsICI3NSAtIEFsbCBIYW5kcyBXb3JraW5nIikgfiAiNyAtIFNpZ25hbCA3LTUiKQpIaWdoZXN0X3NldmVyaXR5IDwtIGJ1aWxkaW5nX2ZpcmUgJT4lCiAgZmlsdGVyKEhJR0hFU1RfTEVWRUxfREVTQyA9PSAiNyAtIFNpZ25hbCA3LTUiKQpgYGAKCmBgYHtyfQpjb250ZW50IDwtIHBhc3RlKCJTZXZlcml0eToiLCBIaWdoZXN0X3NldmVyaXR5JEhJR0hFU1RfTEVWRUxfREVTQywiPGJyL2M+IiwKICAgICAgICAgICAgICAgICAiV2hlbjoiLEhpZ2hlc3Rfc2V2ZXJpdHkkSU5DSURFTlRfREFURV9USU1FLCI8YnIvYz4iLAogICAgICAgICAgICAgICAgICJXaGVyZToiLEhpZ2hlc3Rfc2V2ZXJpdHkkUFJPUEVSVFlfVVNFX0RFU0MsIjxici9jIikKYGBgCgpgYGB7cn0KbSA8LSBsZWFmbGV0KEhpZ2hlc3Rfc2V2ZXJpdHkpICU+JQogIGFkZFRpbGVzKCkKbTEgPC0gbSAlPiUKICBhZGRDaXJjbGVzKGxuZyA9IH5sb24sIGxhdCA9IH5sYXQsIHBvcHVwID0gY29udGVudCkKYGBgCgojIyMjIDIuIExheWVycyBhbmQgQ2x1c3RlcnMKKGEpIENvbG9yIGJ5IFR5cGUgb2YgUHJvcGVydHkgCmBgYHtyfQpIaWdoZXN0X3NldmVyaXR5JFBST1BFUlRZX1VTRV9ERVNDIDwtIGNhc2Vfd2hlbihncmVwbCgiZHdlbGxpbmciLEhpZ2hlc3Rfc2V2ZXJpdHkkUFJPUEVSVFlfVVNFX0RFU0MpPT0gVFJVRSB8IEhpZ2hlc3Rfc2V2ZXJpdHkkUFJPUEVSVFlfVVNFX0RFU0MgJWluJSBjKCI0MDAgLSBSZXNpZGVudGlhbCwgb3RoZXIgICIsIjQzOSAtIEJvYXJkaW5nL3Jvb21pbmcgaG91c2UsIHJlc2lkZW50aWFsIGhvdGVscyAiLCIgNDQ5IC0gSG90ZWwvbW90ZWwsIGNvbW1lcmNpYWwiLCIgNDYwIC0gRG9ybWl0b3J5LXR5cGUgcmVzaWRlbmNlLCBvdGhlciAiLCI0NjQgLSBCYXJyYWNrcywgZG9ybWl0b3J5ICIpIH4gIkR3ZWxsaW5nLCBSZXNpZGVudGlhbCIsSGlnaGVzdF9zZXZlcml0eSRQUk9QRVJUWV9VU0VfREVTQyVpbiUgYygiIDE2MSAtIFJlc3RhdXJhbnQgb3IgY2FmZXRlcmlhIikgfiJSZXN0YXVyYW50IiwgSGlnaGVzdF9zZXZlcml0eSRQUk9QRVJUWV9VU0VfREVTQyVpbiUgYygiODgxIC0gUGFya2luZyBnYXJhZ2UsIChkZXRhY2hlZCByZXNpZGVudGlhbCBnYXJhZ2UpIiwiOTY1IC0gVmVoaWNsZSBwYXJraW5nIGFyZWEgIiwiIDg4MiAtIFBhcmtpbmcgZ2FyYWdlLCBnZW5lcmFsIHZlaGljbGUgICIpIH4iUGFya2luZyIsIEhpZ2hlc3Rfc2V2ZXJpdHkkUFJPUEVSVFlfVVNFX0RFU0MlaW4lIGMoIjU2NCAtIExhdW5kcnksIGRyeSBjbGVhbmluZyAiLCI1NzkgLSBNb3RvciB2ZWhpY2xlIG9yIGJvYXQgc2FsZXMsIHNlcnZpY2VzLCByZXBhaXIiLCI1NTkgLSBSZWNyZWF0aW9uYWwsIGhvYmJ5LCBob21lIHJlcGFpciBzYWxlcywgcGV0IHN0b3JlICIsIjUwMCAtIE1lcmNhbnRpbGUsIGJ1c2luZXNzLCBvdGhlciAgICIsIjU0OSAtIFNwZWNpYWx0eSBzaG9wIiwiIDUxOSAtIEZvb2QgYW5kIGJldmVyYWdlIHNhbGVzLCBncm9jZXJ5IHN0b3JlICIsIjU4MCAtIEdlbmVyYWwgcmV0YWlsLCBvdGhlciIsIjU1NyAtIFBlcnNvbmFsIHNlcnZpY2UsIGluY2x1ZGluZyBiYXJiZXIgJiBiZWF1dHkgc2hvcHMgIiwiNTExIC0gQ29udmVuaWVuY2Ugc3RvcmUgICAgIiwiNTM5IC0gSG91c2Vob2xkIGdvb2RzLCBzYWxlcywgcmVwYWlycyAiLCIxODMgLSBNb3ZpZSB0aGVhdGVyICIsIjE4MCAtIFN0dWRpby90aGVhdGVyLCBvdGhlciAiLCIxNjAgLSBFYXRpbmcsIGRyaW5raW5nIHBsYWNlcywgb3RoZXIgIiwiNTI5IC0gVGV4dGlsZSwgd2VhcmluZyBhcHBhcmVsIHNhbGVzIiwiNTgxIC0gRGVwYXJ0bWVudCBvciBkaXNjb3VudCBzdG9yZSIsIjE4NiAtIEZpbG0vbW92aWUgcHJvZHVjdGlvbiBzdHVkaW8iLCIxODEgLSBMaXZlIHBlcmZvcm1hbmNlIHRoZWF0ZXIiLCIyNTQgLSBEYXkgY2FyZSwgaW4gY29tbWVyY2lhbCBwcm9wZXJ0eSIsIjE2MSAtIFJlc3RhdXJhbnQgb3IgY2FmZXRlcmlhIiwiMTQyIC0gQ2x1YmhvdXNlICIsIjE0MCAtIENsdWJzLCBvdGhlciIsIjE0MyAtIFlhY2h0IENsdWIgIiwiMTYyIC0gQmFyIG9yIG5pZ2h0Y2x1YiIsIjE0NCAtIENhc2lubywgZ2FtYmxpbmcgY2x1YnMiLCIxNDEgLSBBdGhsZXRpYy9oZWFsdGggY2x1YiIpIH4iQ29tbWVyY2lhbCBQcm9wZXJ0eSIsIEhpZ2hlc3Rfc2V2ZXJpdHkkUFJPUEVSVFlfVVNFX0RFU0MlaW4lIGMoIiAxMzEgLSBDaHVyY2gsIG1vc3F1ZSwgc3luYWdvZ3VlLCB0ZW1wbGUsIGNoYXBlbCIpICB+ICJSZWxpZ2lvdXMgUGxhY2VzIiwgSGlnaGVzdF9zZXZlcml0eSRQUk9QRVJUWV9VU0VfREVTQyVpbiUgYygiIDE3MyAtIEJ1cyBzdGF0aW9uICAgICAiLCIxNzAgLSBQYXNzZW5nZXIgdGVybWluYWwsIG90aGVyICIsIjE3NCAtIFJhcGlkIHRyYW5zaXQgc3RhdGlvbiAiKSAgfiAiUHVibGljIFRyYW5zcG9ydGF0aW9uIiwgZ3JlcGwoIkNsaW5pYyIsSGlnaGVzdF9zZXZlcml0eSRQUk9QRVJUWV9VU0VfREVTQykgPT0gVFJVRSB8IEhpZ2hlc3Rfc2V2ZXJpdHkkUFJPUEVSVFlfVVNFX0RFU0MlaW4lIGMoIjMzMSAtIEhvc3BpdGFsIC0gbWVkaWNhbCBvciBwc3ljaGlhdHJpYyAiLCIzMTEgLSAyNC1ob3VyIGNhcmUgTnVyc2luZyBob21lcywgNCBvciBtb3JlIHBlcnNvbnMiLCIgMzMyIC0gSG9zcGljZXMgIiwiIDMwMCAtIEhlYWx0aCBjYXJlLCBkZXRlbnRpb24sICYgY29ycmVjdGlvbiwgb3RoZXIgIiwiMzQyIC0gRG9jdG9yLCBkZW50aXN0IG9yIG9yYWwgc3VyZ2VvbiBvZmZpY2UiLCIgMzIxIC0gTWVudGFsIHJldGFyZGF0aW9uL2RldmVsb3BtZW50IGRpc2FiaWxpdHkgZmFjaWxpdHkiLCIgMzQwIC0gQ2xpbmljcywgZG9jdG9ycyBvZmZpY2VzLCBoZW1vZGlhbHlzaXMgY250ciwgb3RoZXIiLCIzNjMgLSBSZWZvcm1hdG9yeSwganV2ZW5pbGUgZGV0ZW50aW9uIGNlbnRlciIpIH4gIkNsaW5pYyIsCkhpZ2hlc3Rfc2V2ZXJpdHkkUFJPUEVSVFlfVVNFX0RFU0MlaW4lIGMoIjIxMCAtIFNjaG9vbHMsIG5vbi1hZHVsdCwgb3RoZXIiLCIyNDEgLSBBZHVsdCBlZHVjYXRpb24gY2VudGVyLCBjb2xsZWdlIGNsYXNzcm9vbSAgIiwiMjE1IC0gSGlnaCBzY2hvb2wvanVuaW9yIGhpZ2ggc2Nob29sL21pZGRsZSBzY2hvb2wiLCIyMTEgLSBQcmVzY2hvb2wiLCIyMTMgLSBFbGVtZW50YXJ5IHNjaG9vbCwgaW5jbHVkaW5nIGtpbmRlcmdhcnRlbiIpICB+ICJTY2hvb2wiLCBIaWdoZXN0X3NldmVyaXR5JFBST1BFUlRZX1VTRV9ERVNDJWluJSBjKCIxMjMgLSBTdGFkaXVtLCBhcmVuYSIsIiA5MzEgLSBPcGVuIGxhbmQgb3IgZmllbGQgIiwiOTYyIC0gUmVzaWRlbnRpYWwgc3RyZWV0LCByb2FkIG9yIHJlc2lkZW50aWFsIGRyaXZld2F5ICAiLCIzMjIgLSBBbGNvaG9sIG9yIHN1YnN0YW5jZSBhYnVzZSByZWNvdmVyeSBjZW50ZXIiLCI2MTAgLSBFbmVyZ3kgcHJvZHVjdGlvbiBwbGFudCwgb3RoZXIiLCI5MjYgLSBPdXRidWlsZGluZywgcHJvdGVjdGl2ZSBzaGVsdGVyICIsIjAwMCAtIFByb3BlcnR5IFVzZSwgb3RoZXIiLCIgOTgxIC0gQ29uc3RydWN0aW9uIHNpdGUiLCI0NTkgLSBSZXNpZGVudGlhbCBib2FyZCBhbmQgY2FyZSAgIiwiIDE1MiAtIE11c2V1bSAiLCIxMzAgLSBQbGFjZXMgb2Ygd29yc2hpcCwgZnVuZXJhbCBwYXJsb3JzLCBvdGhlciIsIjk2MyAtIFN0cmVldCBvciByb2FkIGluIGNvbW1lcmNpYWwgYXJlYSAiLCI2NDggLSBTYW5pdGF0aW9uIHV0aWxpdHkiLCIxMTAgLSBGaXhlZC11c2UgcmVjcmVhdGlvbiBwbGFjZXMsIG90aGVyIiwiNTcxIC0gU2VydmljZSBzdGF0aW9uLCBnYXMgc3RhdGlvbiAiLCIxODIgLSBBdWRpdG9yaXVtLCBjb25jZXJ0IGhhbGwgICIsIiA4MDggLSBPdXRidWlsZGluZyBvciBzaGVkICIsIiAxMjEgLSBCYWxscm9vbSwgZ3ltbmFzaXVtICAiLCIxMTIgLSBCaWxsaWFyZCBjZW50ZXIsIHBvb2wgaGFsbCAiLCI1NjkgLSBQcm9mZXNzaW9uYWwgc3VwcGxpZXMsIHNlcnZpY2VzICIsIjEyNCAtIFBsYXlncm91bmQiLCI2MzUgLSBDb21wdXRlciBjZW50ZXIiLCIxMzQgLSBGdW5lcmFsIHBhcmxvciIsIjk4NCAtIEluZHVzdHJpYWwgcGxhbnQgeWFyZCAtIGFyZWEiLCI2MjkgLSBMYWJvcmF0b3J5IG9yIHNjaWVuY2UgbGFiYWJvcmF0b3J5IiwiOTM2IC0gVmFjYW50IGxvdCIsIjI1MCAtIERheSBjYXJlLCBvdGhlciAoQ29udmVyc2lvbiBvbmx5KSIsIjYxNSAtIEVsZWN0cmljLWdlbmVyYXRpbmcgcGxhbnQgIiwiNjM5IC0gQ29tbXVuaWNhdGlvbnMgY2VudGVyIiwiODk4IC0gRG9jaywgbWFyaW5hLCBwaWVyLCB3aGFyZiAiLCI5NTIgLSBSYWlscm9hZCB5YXJkICIpICB+ICJQdWJsaWMgQXJlYSIsSGlnaGVzdF9zZXZlcml0eSRQUk9QRVJUWV9VU0VfREVTQyVpbiUgYygiODkxIC0gV2FyZWhvdXNlIiwiODk5IC0gUmVzaWRlbnRpYWwgb3Igc2VsZi1zdG9yYWdlIHVuaXRzICIsIjg4MCAtIFZlaGljbGUgc3RvcmFnZSwgb3RoZXIgICIsIjgwMCAtIFN0b3JhZ2UsIG90aGVyIiwiODM5IC0gUmVmcmlnZXJhdGVkIHN0b3JhZ2UgIiwiODA3IC0gT3V0c2lkZSBtYXRlcmlhbCBzdG9yYWdlIGFyZWEiKSAgfiAiV2FyZWhvdXNlL1N0b3JhZ2UiLEhpZ2hlc3Rfc2V2ZXJpdHkkUFJPUEVSVFlfVVNFX0RFU0MlaW4lIGMoIiA1OTkgLSBCdXNpbmVzcyBvZmZpY2UiLCI1OTMgLSBPZmZpY2U6ICB2ZXRlcmluYXJ5IG9yIHJlc2VhcmNoICIsIjE1MCAtIFB1YmxpYyBvciBnb3Zlcm5tZW50LCBvdGhlciAgICIsIjU5NiAtIFBvc3Qgb2ZmaWNlIG9yIG1haWxpbmcgZmlybXMiLCIzNjUgLSBQb2xpY2Ugc3RhdGlvbiIsIjE1NSAtIENvdXJ0aG91c2UiLCJCYW5rIikgIH4gIk9mZmljZSIpCmBgYAoKYGBge3J9CnBhbCA9IGNvbG9yRmFjdG9yKCJTZXQxIiwgZG9tYWluID0gSGlnaGVzdF9zZXZlcml0eSRQUk9QRVJUWV9VU0VfREVTQykKY29sb3JfcHJvID0gcGFsKEhpZ2hlc3Rfc2V2ZXJpdHkkUFJPUEVSVFlfVVNFX0RFU0MpCm0yIDwtIG0gJT4lCiAgYWRkQ2lyY2xlcyhsbmcgPSB+bG9uLCBsYXQgPSB+bGF0LCBjb2xvciA9IGNvbG9yX3Bybyxwb3B1cCA9IH5hcy5jaGFyYWN0ZXIoSGlnaGVzdF9zZXZlcml0eSRQUk9QRVJUWV9VU0VfREVTQykpICU+JQphZGRMZWdlbmQocGFsID0gcGFsLCB2YWx1ZXMgPSB+IEhpZ2hlc3Rfc2V2ZXJpdHkkUFJPUEVSVFlfVVNFX0RFU0MsIHRpdGxlID0gIlR5cGUgb2YgUHJvcGVydHkiKQptMgpgYGAKCihiKSBDbHVzdGVyIApgYGB7cn0KbTMgPC0gbSAlPiUKYWRkQ2lyY2xlTWFya2VycyhsbmcgPSB+bG9uLCBsYXQgPSB+bGF0LGNvbG9yID0gY29sb3JfcHJvLCBwb3B1cCA9IGNvbnRlbnQsIGNsdXN0ZXJPcHRpb25zID0gbWFya2VyQ2x1c3Rlck9wdGlvbnMoKSkKbTMKYGBgCgojIyMjIDMuIEZpcmUgSG91c2UKYGBge3J9Cm1fbDEgPC0gbGVhZmxldCgpICU+JQphZGRUaWxlcygpJT4lCmFkZENpcmNsZU1hcmtlcnMoZGF0YSA9IEhpZ2hlc3Rfc2V2ZXJpdHkgLGdyb3VwID0gIkluY2lkZW50cyIsIHJhZGl1cyAgPSB+IEhpZ2hlc3Rfc2V2ZXJpdHkkVU5JVFNfT05TQ0VORSxwb3B1cCA9IGNvbnRlbnQpICU+JQphZGRDaXJjbGVNYXJrZXJzKGRhdGEgPSBGRE5ZLGdyb3VwID0gIkZpcmVob3VzZXMiLGNvbG9yID0gIiNGMDUiLHBvcHVwID0gfmFzLmNoYXJhY3RlcihGRE5ZJEZhY2lsaXR5TmFtZSksY2x1c3Rlck9wdGlvbnMgPSBtYXJrZXJDbHVzdGVyT3B0aW9ucygpKSAlPiUKYWRkTGF5ZXJzQ29udHJvbCgKYmFzZUdyb3VwcyA9IGMoIk5ZQ21hcCIpLApvdmVybGF5R3JvdXBzID0gYygiSW5jaWRlbnRzIiwiRmlyZWhvdXNlcyIpKQptX2wxCmBgYAoKIyMjIyA0LiBEaXN0YW5jZSBmcm9tIEZpcmVob3VzZSBhbmQgUmVzcG9uc2UgVGltZSAKKGEpIENhbGN1bGF0ZSBEaXN0YW5jZSAKYGBge3J9CmJ1aWxkaW5nX2ZpcmUxPC0gYnVpbGRpbmdfZmlyZSAlPiUKbXV0YXRlKGRpc3RpbWUgPSBkaWZmdGltZShzdHJwdGltZShhcy5jaGFyYWN0ZXIoYnVpbGRpbmdfZmlyZSRBUlJJVkFMX0RBVEVfVElNRSksIiVtLyVkLyVZICVJOiVNOiVTICVwIiksc3RycHRpbWUoYXMuY2hhcmFjdGVyKGJ1aWxkaW5nX2ZpcmUkSU5DSURFTlRfREFURV9USU1FKSwiJW0vJWQvJVkgJUk6JU06JVMgJXAiKSx1bml0cyA9ICJzZWNzIikpCmBgYAoKYGBge3J9CmxpYnJhcnkoZ2Vvc3BoZXJlKQpsaWJyYXJ5KFNvREEpCmxpYnJhcnkoZ2dwbG90MikKYGBgCgpgYGB7cn0KZmlyZV9sb25fbGF0IDwtIGRhdGEuZnJhbWUoYnVpbGRpbmdfZmlyZTEkbG9uLCBidWlsZGluZ19maXJlMSRsYXQpCkZETllfbG9uX2xhdCA8LSBkYXRhLmZyYW1lKEZETlkkTG9uZ2l0dWRlLCBGRE5ZJExhdGl0dWRlKQphIDwtICBkaXN0bShhcy52ZWN0b3IoZmlyZV9sb25fbGF0KSxhcy52ZWN0b3IoRkROWV9sb25fbGF0KSxmdW4gPSBkaXN0R2VvKQpgYGAKCmBgYHtyfQpidWlsZGluZ19maXJlMiA8LSBidWlsZGluZ19maXJlMSAlPiUKbXV0YXRlKG1pbmRpc3QgPSBOQSkKZm9yIChpIGluIDE6bnJvdyhhKSkgewpidWlsZGluZ19maXJlMiRtaW5kaXN0W2ldIDwtIG1pbihhW2ksXSxuYS5ybSA9IFRSVUUpCn0KYGBgCgpgYGB7cn0KcF9kaXN0YW5jZSA8LSBnZ3Bsb3QoYnVpbGRpbmdfZmlyZTIsIGFlcyh4ID0gbWluZGlzdCwgeSA9IGRpc3RpbWUpKSArIGdlb21fcG9pbnQoKSArIHhsaW0oMCw1MDAwKSArIHlsaW0oMCwxMDAwKSArIGZhY2V0X3dyYXAoYXMuZmFjdG9yKGJ1aWxkaW5nX2ZpcmUyJEhJR0hFU1RfTEVWRUxfREVTQykpICsgZ2VvbV9zbW9vdGgoKSArIGxhYnMoeD0iTmVhcmVzdCBGaXJlaG91c2UgaW4gbWV0ZXJzIiwgeSA9ICJGaXJzdCBhcnJpdmFsIGluIHNlY3MiLCB0aXRsZSA9ICJEaXN0YW5jZSBGcm9tIEZpcmVob3VzZSBWLlMuIFJlc3BvbnNlIFRpbWUiKQpwX2Rpc3RhbmNlCmBgYAoKKGIpIE1hcCBvZiBSZXNwb25zZSBUaW1lcyAKYGBge3J9CmxpYnJhcnkocmdkYWwpCmxpYnJhcnkoZ2VvanNvbikKYGBgCgpgYGB7cn0KbGlicmFyeShnZW9qc29uaW8pCmBgYAoKYGBge3J9Cm55Y2l0eSA8LSByZWFkT0dSKCIvVXNlcnMvY2Fyb2xpbmV5dS9EZXNrdG9wL2Jvcm91Z2hfYm91bmRhcmllcy5nZW9qc29uIiwgdmVyYm9zZSA9IEZBTFNFKQpgYGAKCmBgYHtyfQpjb250ZW50X3RpbWUgPC0gcGFzdGUoIlNldmVyaXR5OiIsIGJ1aWxkaW5nX2ZpcmUyJEhJR0hFU1RfTEVWRUxfREVTQywiPGJyL2M+IiwKIldoZW46IixidWlsZGluZ19maXJlMiRJTkNJREVOVF9EQVRFX1RJTUUsIjxici9jPiIsCiJQcm9wZXJ0eSBUeXBlOiIsYnVpbGRpbmdfZmlyZTIkUFJPUEVSVFlfVVNFX0RFU0MsIjxici9jIiwKIlJlc3BvbnNlIFRpbWU6IixidWlsZGluZ19maXJlMiRkaXN0aW1lLCI8YnIvYyIpCmBgYAoKYGBge3J9CmJ1aWxkaW5nX2ZpcmUzIDwtIGJ1aWxkaW5nX2ZpcmUyICU+JQogIGdyb3VwX2J5KEJPUk9VR0hfREVTQywgSElHSEVTVF9MRVZFTF9ERVNDKSU+JQogIHN1bW1hcmlzZShhdmcgPSBtZWFuKGRpc3RpbWUsIG5hLnJtID0gVFJVRSkpCmBgYAoKYGBge3J9CmJ1aWxkaW5nX2ZpcmUzJEJPUk9VR0hfREVTQyA8LSBzdWJzdHJpbmcoYnVpbGRpbmdfZmlyZTMkQk9ST1VHSF9ERVNDLCA1KQpgYGAKCmBgYHtyfQpueWNpdHlfc2V2ZXJpdHkgPC0gbGVmdF9qb2luKG55Y2l0eUBkYXRhLGJ1aWxkaW5nX2ZpcmUzLCBieSA9IGMoImJvcm9fbmFtZSI9IkJPUk9VR0hfREVTQyIpKQpgYGAKCmBgYHtyfQpteXBhbGV0dGUgPC0gY29sb3JOdW1lcmljKHBhbGV0dGUgPSJZbE9yUmQiLCBkb21haW4gPSBhcy5udW1lcmljKGJ1aWxkaW5nX2ZpcmUzJGF2ZyksYygxODAsMjUwKSkKYGBgCgpgYGB7cn0KTllDX0ZpcmVzIDwtIGxlYWZsZXQoKSAlPiUgCiAgYWRkVGlsZXMoKSAlPiUKICBhZGRQb2x5Z29ucyhkYXRhID0gbnljaXR5LGZpbGxPcGFjaXR5ID0gMSxmaWxsQ29sb3IgPSB+bXlwYWxldHRlKGFzLm51bWVyaWMoYnVpbGRpbmdfZmlyZTMkYXZnKSkpCk5ZQ19GaXJlcwpgYGAKCgpgYGB7cn0KYnVpbGRpbmdfZmlyZTIkWUVBUiA8LSBzdWJzdHJpbmcoYnVpbGRpbmdfZmlyZTIkSU5DSURFTlRfREFURV9USU1FLDcsMTApCmBgYAoKYGBge3J9CnllYXJseSA8LSBidWlsZGluZ19maXJlMiAlPiUKICBncm91cF9ieShZRUFSLCBCT1JPVUdIX0RFU0MpICU+JQogIHN1bW1hcmlzZShhdmcgPSBtZWFuKGRpc3RpbWUsIG5hLnJtID0gVFJVRSkpCmBgYAoKYGBge3J9CmxpYnJhcnkocmVzaGFwZSApCnllYXJseSRCT1JPVUdIX0RFU0MgPC0gc3Vic3RyaW5nKHllYXJseSRCT1JPVUdIX0RFU0MsIDUpCmBgYAoKYGBge3J9Cm55Y19ieV95ZWFyIDwtIGZ1bGxfam9pbih5ZWFybHksIG55Y2l0eUBkYXRhLCBieSA9IGMoIkJPUk9VR0hfREVTQyIgPSAiYm9yb19uYW1lIiApKQpgYGAKCmBgYHtyfQpteXBhbGV0dGUxIDwtIGNvbG9yTnVtZXJpYygiWWxPclJkIiwgZG9tYWluID0gYXMubnVtZXJpYyhueWNfYnlfeWVhciRhdmcpLCBjKDE4MCwyNTApKQpgYGAKCmBgYHtyfQp5ZWFyMjAxMyA8LSBsZWZ0X2pvaW4obnljaXR5QGRhdGEsIHllYXJseVt5ZWFybHkkWUVBUiA9PSAyMDEzLCBdLCBieSA9IGMoImJvcm9fbmFtZSIgPSAiQk9ST1VHSF9ERVNDIikpCmBgYApgYGB7cn0KbnljMjAxMyA8LSBsZWFmbGV0KCklPiUKICBhZGRUaWxlcygpICU+JQogIGFkZFBvbHlnb25zKGRhdGEgPSBueWNpdHksIGZpbGxDb2xvciA9IH4gbXlwYWxldHRlMShhcy5udW1lcmljKHllYXIyMDEzJGF2ZykpLAogICAgICAgICAgICAgIGZpbGxPcGFjaXR5ID0gMSklPiUKICBhZGRMZWdlbmQocGFsID0gbXlwYWxldHRlMSwgdmFsdWVzID0gYXMubnVtZXJpYyhueWNfYnlfeWVhciRhdmcpLCB0aXRsZSA9ICJZRUFSIDIwMTMiLCAidG9wcmlnaHQiKQpgYGAKCgpgYGB7cn0KeWVhcjIwMTQgPC0gbGVmdF9qb2luKG55Y2l0eUBkYXRhLCB5ZWFybHlbeWVhcmx5JFlFQVIgPT0gMjAxNCwgXSwgYnkgPSBjKCJib3JvX25hbWUiID0gIkJPUk9VR0hfREVTQyIpKQpueWMyMDE0IDwtIGxlYWZsZXQoKSU+JQogIGFkZFRpbGVzKCkgJT4lCiAgYWRkUG9seWdvbnMoZGF0YSA9IG55Y2l0eSwgZmlsbENvbG9yID0gfiBteXBhbGV0dGUxKGFzLm51bWVyaWMoeWVhcjIwMTQkYXZnKSksCiAgICAgICAgICAgICAgZmlsbE9wYWNpdHkgPSAxKSU+JQogIGFkZExlZ2VuZChwYWwgPSBteXBhbGV0dGUxLCB2YWx1ZXMgPSBhcy5udW1lcmljKG55Y19ieV95ZWFyJGF2ZyksIHRpdGxlID0gIllFQVIgMjAxNCIsICJ0b3ByaWdodCIpCgpgYGAKYGBge3J9CnllYXIyMDE1IDwtIGxlZnRfam9pbihueWNpdHlAZGF0YSwgeWVhcmx5W3llYXJseSRZRUFSID09IDIwMTUsIF0sIGJ5ID0gYygiYm9yb19uYW1lIiA9ICJCT1JPVUdIX0RFU0MiKSkKbnljMjAxNTwtIGxlYWZsZXQoKSU+JQogIGFkZFRpbGVzKCkgJT4lCiAgYWRkUG9seWdvbnMoZGF0YSA9IG55Y2l0eSwgZmlsbENvbG9yID0gfiBteXBhbGV0dGUxKGFzLm51bWVyaWMoeWVhcjIwMTUkYXZnKSksCiAgICAgICAgICAgICAgZmlsbE9wYWNpdHkgPSAxKSU+JQogIGFkZExlZ2VuZChwYWwgPSBteXBhbGV0dGUxLCB2YWx1ZXMgPSBhcy5udW1lcmljKG55Y19ieV95ZWFyJGF2ZyksIHRpdGxlID0gIllFQVIgMjAxNSIsICJ0b3ByaWdodCIpCmBgYAoKYGBge3J9CnllYXIyMDE2IDwtIGxlZnRfam9pbihueWNpdHlAZGF0YSwgeWVhcmx5W3llYXJseSRZRUFSID09IDIwMTYsIF0sIGJ5ID0gYygiYm9yb19uYW1lIiA9ICJCT1JPVUdIX0RFU0MiKSkKbnljMjAxNiA8LSBsZWFmbGV0KCklPiUKICBhZGRUaWxlcygpICU+JQogIGFkZFBvbHlnb25zKGRhdGEgPSBueWNpdHksIGZpbGxDb2xvciA9IH4gbXlwYWxldHRlMShhcy5udW1lcmljKHllYXIyMDE2JGF2ZykpLAogICAgICAgICAgICAgIGZpbGxPcGFjaXR5ID0gMSklPiUKICBhZGRMZWdlbmQocGFsID0gbXlwYWxldHRlMSwgdmFsdWVzID0gYXMubnVtZXJpYyhueWNfYnlfeWVhciRhdmcpLCB0aXRsZSA9ICJZRUFSIDIwMTYiLCAidG9wcmlnaHQiKQpgYGAKCmBgYHtyfQp5ZWFyMjAxNyA8LSBsZWZ0X2pvaW4obnljaXR5QGRhdGEsIHllYXJseVt5ZWFybHkkWUVBUiA9PSAyMDE3LCBdLCBieSA9IGMoImJvcm9fbmFtZSIgPSAiQk9ST1VHSF9ERVNDIikpCm55YzIwMTcgPC0gbGVhZmxldCgpJT4lCiAgYWRkVGlsZXMoKSAlPiUKICBhZGRQb2x5Z29ucyhkYXRhID0gbnljaXR5LCBmaWxsQ29sb3IgPSB+IG15cGFsZXR0ZTEoYXMubnVtZXJpYyh5ZWFyMjAxNyRhdmcpKSwKICAgICAgICAgICAgICBmaWxsT3BhY2l0eSA9IDEpJT4lCiAgYWRkTGVnZW5kKHBhbCA9IG15cGFsZXR0ZTEsIHZhbHVlcyA9IGFzLm51bWVyaWMobnljX2J5X3llYXIkYXZnKSwgdGl0bGUgPSAiWUVBUiAyMDE3IiwgInRvcHJpZ2h0IikKYGBgCmBgYHtyfQp5ZWFyMjAxOCA8LSBsZWZ0X2pvaW4obnljaXR5QGRhdGEsIHllYXJseVt5ZWFybHkkWUVBUiA9PSAyMDE4LCBdLCBieSA9IGMoImJvcm9fbmFtZSIgPSAiQk9ST1VHSF9ERVNDIikpCm55YzIwMTggPC0gbGVhZmxldCgpJT4lCiAgYWRkVGlsZXMoKSAlPiUKICBhZGRQb2x5Z29ucyhkYXRhID0gbnljaXR5LCBmaWxsQ29sb3IgPSB+IG15cGFsZXR0ZTEoYXMubnVtZXJpYyh5ZWFyMjAxOCRhdmcpKSwKICAgICAgICAgICAgICBmaWxsT3BhY2l0eSA9IDEpJT4lCiAgYWRkTGVnZW5kKHBhbCA9IG15cGFsZXR0ZTEsIHZhbHVlcyA9IGFzLm51bWVyaWMobnljX2J5X3llYXIkYXZnKSwgdGl0bGUgPSAiWUVBUiAyMDE4IiwgInRvcHJpZ2h0IikKYGBgCgpgYGB7cn0KbGlicmFyeShtYXB2aWV3KQpsZWFmc3luYzo6c3luYyhueWMyMDEzLG55YzIwMTQsbnljMjAxNSxueWMyMDE2LG55YzIwMTcsbnljMjAxOCkKYGBgCgoKCgoKCgo=